/*
 * Copyright (c) 2007 jNetX.
 * http://www.jnetx.com
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * jNetX. You shall not disclose such Confidential Information and
 * shall use it only in accordance with the terms of the license
 * agreement you entered into with jNetX.
 *
 * $Id$
 */
package com.jnetx.javax.sip.header;

import javax.sip.InvalidArgumentException;
import javax.sip.header.ViaHeader;
import java.text.ParseException;

/**
 * @author <a href="mailto:dparhonin@jnetx.ru">Dmitry Parhonin</a>
 * @version $Revision$
 */
public class ViaHeaderImpl extends ParametrizedHeaderBase implements ViaHeader {
    private String host;
    private Integer port;
    private String transport;
    private String protocol;

    private static final ViaHeaderParser parser = new ViaHeaderParser();

    protected HeaderParser getParser() {
        return parser;
    }

    public ViaHeaderImpl() {
        super(ViaHeader.NAME);
    }

    ViaHeaderImpl(byte[] data, int start, int length) {
        super(ViaHeader.NAME, data, start, length);
    }

    public Object clone() {
        final ViaHeaderImpl header = new ViaHeaderImpl();
        header.cloneBase(this);
        if (parsed) {
            header.cloneParameters(this);
            header.host = this.host;
            header.port = this.port;
            header.transport = this.transport;
            header.protocol = this.protocol;
        }
        return header;
    }

    protected String getValueAsString() {
        final StringBuilder sb = new StringBuilder();
        sb.append(protocol).append('/').append(transport).append(' ').append(host);
        if (port != -1)
            sb.append(':').append(port);
        return sb.toString();
    }

    /**
     * Set the host part of this ViaHeader to the newly supplied <code>host</code>
     * parameter.
     *
     * @param host the new value of the host of this ViaHeader.
     * @throws java.text.ParseException which signals that an error has been reached
     *                                  unexpectedly while parsing the host value.
     */
    public void setHost(String host) throws ParseException {
        parse();
        this.host = host;
        invalidateHeaderData();
    }

    /**
     * Returns the host part of this ViaHeader.
     *
     * @return the string value of the host.
     */
    public String getHost() {
        parse();
        return host;
    }

    /**
     * Set the port part of this ViaHeader to the newly supplied <code>port</code>
     * parameter.
     *
     * @param port the new integer value of the port of this ViaHeader.
     * @throws javax.sip.InvalidArgumentException
     *          when the port value is not -1 and <1 or >65535
     */
    public void setPort(int port) throws InvalidArgumentException {
        parse();
        if (port == -1)
            this.port = null;
        else if (port < 1 || port > 65535)
            throw new IllegalArgumentException("The port value is illegal: " + port);
        else
            this.port = port;
        invalidateHeaderData();
    }

    /**
     * Returns the port part of this ViaHeader.
     *
     * @return the integer value of the port, -1 if not present
     */
    public int getPort() {
        parse();
        if (this.port != null)
            return port;
        else
            return -1;
    }

    /**
     * Returns the value of the transport parameter.
     *
     * @return the string value of the transport paramter of the ViaHeader.
     */
    public String getTransport() {
        parse();
        return transport;
    }

    /**
     * Sets the value of the transport. This parameter specifies
     * which transport protocol to use for sending requests and responses to
     * this entity. The following values are defined: "udp", "tcp", "sctp",
     * "tls", but other values may be used also.
     *
     * @param transport new value for the transport parameter.
     * @throws java.text.ParseException which signals that an error has been reached
     *                                  unexpectedly while parsing the transport value.
     */
    public void setTransport(String transport) throws ParseException {
        parse();
        this.transport = transport;
        invalidateHeaderData();
    }

    /**
     * Returns the value of the protocol used.
     *
     * @return the string value of the protocol paramter of the ViaHeader.
     */
    public String getProtocol() {
        parse();
        return protocol;
    }

    /**
     * Sets the value of the protocol parameter. This parameter specifies
     * which protocol is used, for example "SIP/2.0".
     *
     * @param protocol new value for the protocol parameter.
     * @throws java.text.ParseException which signals that an error has been reached
     *                                  unexpectedly while parsing the protocol value.
     */
    public void setProtocol(String protocol) throws ParseException {
        parse();
        this.protocol = protocol;
        invalidateHeaderData();
    }

    /**
     * Returns the value of the ttl parameter, or -1 if this is not set.
     *
     * @return the integer value of the <code>ttl</code> parameter.
     */
    public int getTTL() {
        parse();
        final String ttlStr = getParameter("ttl");
        if (ttlStr != null)
            return Integer.parseInt(ttlStr);
        else
            return -1;
    }

    /**
     * Sets the value of the ttl parameter. The ttl parameter specifies the
     * time-to-live value when packets are sent using UDP multicast.
     *
     * @param ttl new value of the ttl parameter.
     * @throws javax.sip.InvalidArgumentException
     *          if supplied value is less than zero or
     *          greater than 255, excluding -1 the default not set value.
     */
    public void setTTL(int ttl) throws InvalidArgumentException {
        parse();
        if (ttl == -1)
            removeParameter("ttl");
        else if (ttl > 255 || ttl < 0)
            throw new IllegalArgumentException("The TTL parameter is invalid!");
        else
            try {
                setParameter("ttl", Integer.toString(ttl));
            } catch (ParseException e) {
                throw new IllegalArgumentException("Cannot set the TTL value!", e);
            }
        invalidateHeaderData();
    }

    /**
     * Returns the value of the <code>maddr</code> parameter, or null if this
     * is not set.
     *
     * @return the string value of the maddr parameter.
     */
    public String getMAddr() {
        parse();
        return getParameter("maddr");
    }

    /**
     * Sets the value of the <code>maddr</code> parameter of this ViaHeader. The
     * maddr parameter indicates the server address to be contacted for this
     * user, overriding any address derived from the host field.
     *
     * @param mAddr new value of the <code>mAddr</code> parameter.
     * @throws java.text.ParseException which signals that an error has been reached
     *                                  unexpectedly while parsing the mAddr value.
     */
    public void setMAddr(String mAddr) throws ParseException {
        parse();
        setParameter("maddr", mAddr);
        invalidateHeaderData();
    }

    /**
     * Gets the received paramater of the ViaHeader. Returns null if received
     * does not exist.
     *
     * @return the string received value of ViaHeader.
     */
    public String getReceived() {
        parse();
        return getParameter("received");
    }

    /**
     * Sets the received parameter of ViaHeader.
     *
     * @param received the newly supplied received parameter.
     * @throws java.text.ParseException which signals that an error has been reached
     *                                  unexpectedly while parsing the received value.
     */
    public void setReceived(String received) throws ParseException {
        parse();
        setParameter("received", received);
        invalidateHeaderData();
    }

    /**
     * Gets the branch paramater of the ViaHeader. Returns null if branch
     * does not exist.
     *
     * @return the string branch value of ViaHeader.
     */
    public String getBranch() {
        parse();
        return getParameter("branch");
    }

    /**
     * Sets the branch parameter of the ViaHeader to the newly supplied
     * branch value. Note that when sending a Request within a transaction,
     * branch id management will be the responsibility of the SipProvider;
     * that is the application should not set this value. This method should
     * only be used by the application when sending Requests outside of a
     * transaction.
     *
     * @param branch the new string branch parmameter of the ViaHeader.
     * @throws java.text.ParseException which signals that an error has been reached
     *                                  unexpectedly while parsing the branch value.
     */
    public void setBranch(String branch) throws ParseException {
        parse();
        setParameter("branch", branch);
        invalidateHeaderData();
    }

    /**
     * Set the rport part of this ViaHeader. This method indicates to the
     * remote party that you want it to use rport. It is the applications
     * responsisbility to call this method to inform the implementation to set
     * the value of the rport. This allows a client
     * to request that the server send the response back to the source IP
     * address and port from which the request originated.
     * See <a href = "http://www.ietf.org/rfc/rfc3581.txt">RFC3581</a>
     *
     * @throws javax.sip.InvalidArgumentException
     *          if rport value is an illegal integer ( <=0 ).
     */
    public void setRPort() throws InvalidArgumentException {
        parse();
        try {
            setParameter("rport", null); //todo Implement rport setting
        } catch (ParseException e) {
            throw new InvalidArgumentException("Cannot set rport parameter!", e);
        }
        invalidateHeaderData();
    }

    /**
     * Returns the rport part of this ViaHeader.
     *
     * @return the integer value of the rport or -1 if the rport parameter
     *         is not set.
     */
    public int getRPort() {
        parse();
        final String rportStr = getParameter("rport");
        if (rportStr == null)
            return -1;
        else
            return Integer.parseInt(rportStr);
    }
}
/*
 * $Log$
 */